#include "FreeAddressesBlock.h"


FreeAddressesBlock::FreeAddressesBlock(int blockOffset, int sizeOfBlock, int fileSysDescriptor) :
	offset(blockOffset), blockSize(sizeOfBlock),currentFreeSlotForNewAddress(0), freeAddressesPointer(0), fileDescriptor(fileSysDescriptor) {
	//TODO change:
	//freeAddresses = new int[sizeOfBlock/4];
	nextFreeAddressesBlockIndex = (sizeOfBlock/4)-1;
	for (int i=0; i<sizeOfBlock/4; i++) {
		freeAddresses.push_back(0);
	}
}

FreeAddressesBlock::~FreeAddressesBlock() {}


int FreeAddressesBlock::getNextFreeAddress() {
	if ((freeAddressesPointer == (blockSize/4)-1) || (currentFreeSlotForNewAddress==0)) {
		return -1;
	} else {
		int nextFreeAdr = freeAddresses[freeAddressesPointer];
		removeNextFreeAddress();
		return nextFreeAdr;
	}
}

int FreeAddressesBlock::addFreeAddress(int newFreeAddress) {
	//there is no place for the new address - points to the last cell in array
	if (currentFreeSlotForNewAddress == (blockSize/4) -1) {
		return -1;
	} else {
		freeAddresses[currentFreeSlotForNewAddress] = newFreeAddress;
		currentFreeSlotForNewAddress++;
		return 0;
	}
}

void FreeAddressesBlock::removeNextFreeAddress() {
	freeAddresses[freeAddressesPointer]=0;
	freeAddressesPointer++;
}

int FreeAddressesBlock::getNextFreeAddressesBlock() {
	return freeAddresses[nextFreeAddressesBlockIndex];
}

void FreeAddressesBlock::setNextFreeAddressesBlock(int nextAddress) {
	freeAddresses[nextFreeAddressesBlockIndex] = nextAddress;
}

bool FreeAddressesBlock::hasMoreSpace() {
	return currentFreeSlotForNewAddress < (blockSize/4)-1;
}

bool FreeAddressesBlock::hasPointerToNextBlock() {
	return freeAddresses[nextFreeAddressesBlockIndex]!=0;
}

void FreeAddressesBlock::loadFromPhysicalDisk() {
	int currOffset = offset;
	int buffer;
	while (currOffset<offset+blockSize-4) {
		DiskUtils::readFromDisk(&buffer,currOffset,4);
		if (buffer!=0) {
			addFreeAddress(buffer);
		}
		currOffset+=4;
	}
	DiskUtils::readFromDisk(&buffer,currOffset,4);
	setNextFreeAddressesBlock(buffer);
}

void FreeAddressesBlock::writeToPhysicalDisk() {
	int sizeOfInt = sizeof(int);
	//goes to the location on the the current block
	lseek(fileDescriptor,offset,SEEK_SET);

	for (int i=0; i<blockSize/4; i++) {
		write(fileDescriptor,&freeAddresses[i], sizeOfInt);
	}
}

void FreeAddressesBlock::copyToSelfAndRemoveOther(FreeAddressesBlock& otherBlock) {
	for (int i=0; i<blockSize/4; i++) {
		//int check = otherBlock.getNextFreeAddress();
		addFreeAddress(otherBlock.getNextFreeAddress());
	}
	otherBlock.resetBlock();
	writeToPhysicalDisk();
}

void FreeAddressesBlock::resetBlock() {
	for (int i=0; i<blockSize/4; i++) {
		freeAddresses[i] = 0;
	}
	writeToPhysicalDisk();
}

void FreeAddressesBlock::setOffset(int newOffset) {
	offset = newOffset;
}


void FreeAddressesBlock::printAddresses() {
	for (int i=0; i<blockSize/4; i++) {
		cout << freeAddresses[i] << endl;
	}
}
